﻿using LpbPrj.Client.Tools.Helper;
using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace LpbPrj.Client.Controls.AScan
{
    /// <summary>
    /// 展示A超曲线
    /// </summary>
    public class AScanCanvas : Canvas
    {
        /// <summary>
        /// 数据所在的地址
        /// </summary>
        public static readonly DependencyProperty DataTypeProperty = DependencyProperty.Register("Data", typeof(string), typeof(AScanCanvas), new FrameworkPropertyMetadata(null, propertyChangedCallback: DataChangedCallback));
        public string Data { get => (string)GetValue(DataTypeProperty); set => SetValue(DataTypeProperty, value); }
        private static void DataChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is AScanCanvas ctrl)
            {
                if (e.NewValue != null && e.NewValue is string file)
                {
                    System.Diagnostics.Debug.WriteLine($"DataChangedCallback,DataFile:{file}");
                    if (!string.IsNullOrEmpty(file) && File.Exists(file))
                    {
                        string strJson = File.ReadAllText(file);
                        if (JsonCheck.IsJson(strJson))
                        {
                            var optALine = JsonHelper.ToObject<IolMasterALineResult>(strJson);
                            ctrl.optALine = optALine;
                            ctrl.PreCorneal = optALine?.pkPreCorneal;
                            ctrl.PostCorneal = optALine?.pkPostCorneal;
                            ctrl.PreLens = optALine?.pkPreLens;
                            ctrl.PostLens = optALine?.pkPostLens;
                            ctrl.Retina = optALine?.pkRetina;

                            ctrl.InitCanvas();
                        }
                    }
                }
                else
                {
                    ctrl.optALine = null;
                    ctrl.PreCorneal = null;
                    ctrl.PostCorneal = null;
                    ctrl.PreLens = null;
                    ctrl.PostLens = null;
                    ctrl.Retina = null;
                    ctrl.InitCanvas();
                }
            }
        }

        /// <summary>
        /// 数据
        /// </summary>
        public static readonly DependencyProperty DataALineTypeProperty = DependencyProperty.Register("DataALine", typeof(IolMasterALineResult), typeof(AScanCanvas), new FrameworkPropertyMetadata(null, propertyChangedCallback: DataALineChangedCallback));
        public IolMasterALineResult DataALine { get => (IolMasterALineResult)GetValue(DataALineTypeProperty); set => SetValue(DataALineTypeProperty, value); }
        private static void DataALineChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is AScanCanvas ctrl)
            {
                if (e.NewValue != null && e.NewValue is IolMasterALineResult optALine)
                {
                    System.Diagnostics.Debug.WriteLine($"DataALineChangedCallback");
                    ctrl.optALine = optALine;
                    ctrl.PreCorneal = optALine?.pkPreCorneal;
                    ctrl.PostCorneal = optALine?.pkPostCorneal;
                    ctrl.PreLens = optALine?.pkPreLens;
                    ctrl.PostLens = optALine?.pkPostLens;
                    ctrl.Retina = optALine?.pkRetina;

                    ctrl.InitCanvas();
                }
                else
                {
                    ctrl.optALine = null;
                    ctrl.PreCorneal = null;
                    ctrl.PostCorneal = null;
                    ctrl.PreLens = null;
                    ctrl.PostLens = null;
                    ctrl.Retina = null;
                    ctrl.InitCanvas();
                }
            }
        }

        public static readonly DependencyProperty PreCornealTypeProperty = DependencyProperty.Register("PreCorneal", typeof(int?), typeof(AScanCanvas), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, propertyChangedCallback: UpdateChangedCallback));
        public static readonly DependencyProperty PostCornealTypeProperty = DependencyProperty.Register("PostCorneal", typeof(int?), typeof(AScanCanvas), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, propertyChangedCallback: UpdateChangedCallback));
        public static readonly DependencyProperty PreLensTypeProperty = DependencyProperty.Register("PreLens", typeof(int?), typeof(AScanCanvas), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, propertyChangedCallback: UpdateChangedCallback));
        public static readonly DependencyProperty PostLensTypeProperty = DependencyProperty.Register("PostLens", typeof(int?), typeof(AScanCanvas), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, propertyChangedCallback: UpdateChangedCallback));
        public static readonly DependencyProperty RetinaTypeProperty = DependencyProperty.Register("Retina", typeof(int?), typeof(AScanCanvas), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, propertyChangedCallback: UpdateChangedCallback));

        public static readonly DependencyProperty ScaleXTypeProperty = DependencyProperty.Register("ScaleX", typeof(double), typeof(AScanCanvas), new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, propertyChangedCallback: UpdateChangedCallback));
        public static readonly DependencyProperty ScaleYTypeProperty = DependencyProperty.Register("ScaleY", typeof(double), typeof(AScanCanvas), new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, propertyChangedCallback: UpdateChangedCallback));

        private static void UpdateChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is AScanCanvas ctrl)
            {
                //ctrl.InitCanvas();
            }
        }

        public static readonly DependencyProperty StrokeTypeProperty = DependencyProperty.Register("Stroke", typeof(Brush), typeof(AScanCanvas), new FrameworkPropertyMetadata(Brushes.Black));
        public static readonly DependencyProperty PkVisibilityTypeProperty = DependencyProperty.Register("PkVisibility", typeof(Visibility), typeof(AScanCanvas), new FrameworkPropertyMetadata(Visibility.Collapsed));

        /// <summary>
        /// 是否1:1展示
        /// </summary>
        public static readonly DependencyProperty ActualSizeTypeProperty = DependencyProperty.Register("ActualSize", typeof(bool), typeof(AScanCanvas), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, propertyChangedCallback: ActualSizeChangedCallback));
        public bool ActualSize { get => (bool)GetValue(ActualSizeTypeProperty); set => SetValue(ActualSizeTypeProperty, value); }
        private static void ActualSizeChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is AScanCanvas ctrl)
            {
                ctrl.InitCanvas();
            }
        }



        /// <summary>
        /// 角膜前峰位置,>0有效
        /// </summary>
        public int? PreCorneal { get => (int?)GetValue(PreCornealTypeProperty); set => SetValue(PreCornealTypeProperty, value); }
        /// <summary>
        /// 角膜后峰位置,>0有效
        /// </summary>
		public int? PostCorneal { get => (int?)GetValue(PostCornealTypeProperty); set => SetValue(PostCornealTypeProperty, value); }
        /// <summary>
        /// 晶体前峰位置,>0有效
        /// </summary>
        public int? PreLens { get => (int?)GetValue(PreLensTypeProperty); set => SetValue(PreLensTypeProperty, value); }
        /// <summary>
        /// 晶体后峰位置,>0有效
        /// </summary>
        public int? PostLens { get => (int?)GetValue(PostLensTypeProperty); set => SetValue(PostLensTypeProperty, value); }
        /// <summary>
        /// 视网膜峰位置,>0有效
        /// </summary>
        public int? Retina { get => (int?)GetValue(RetinaTypeProperty); set => SetValue(RetinaTypeProperty, value); }
        /// <summary>
        /// 是否显示波峰位置
        /// </summary>
        public Visibility PkVisibility { get => (Visibility)GetValue(PkVisibilityTypeProperty); set => SetValue(PkVisibilityTypeProperty, value); }
        /// <summary>
        /// 缩放X
        /// </summary>
        public double ScaleX { get => (double)GetValue(ScaleXTypeProperty); set => SetValue(ScaleXTypeProperty, value); }
        /// <summary>
        /// 缩放Y
        /// </summary>
        public double ScaleY { get => (double)GetValue(ScaleYTypeProperty); set => SetValue(ScaleYTypeProperty, value); }

        /// <summary>
        /// 曲线颜色
        /// </summary>
        public Brush Stroke { get => (Brush)GetValue(StrokeTypeProperty); set => SetValue(StrokeTypeProperty, value); }

        private IolMasterALineResult optALine = null;
        private double width = 0.0;
        private double height = 0.0;
        private int offsetX = 0;
        private int offsetY = 10;//图像整体向上偏移10个像素，负值不显示的时候
        private bool ShowNegative = false;//负值是否显示
        private short ShowALineMax = 1024;//A超曲线展示的时候的最大值

        /// <summary>
        /// 构造函数，不要使用Onrender重绘控件，否则事件均不响应；而是采用在Canvas上叠加图像的形式来展示
        /// </summary>
        public AScanCanvas()
        {
            //必须是对背景色赋值，否则鼠标操作无响应
            Background = Brushes.Transparent;
            ClipToBounds = true; //剪切此元素的内容
            IsHitTestVisible = true;

            if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
            {
                SizeChanged += (object sender, SizeChangedEventArgs e) =>
                {
                    width = ActualWidth;
                    height = ActualHeight;
                    System.Diagnostics.Debug.WriteLine($"SizeChanged,W:{width},H:{height}");
                    InitCanvas();
                };
            }
        }

        /// <summary>
        /// 初始化画板
        /// </summary>
        private void InitCanvas()
        {
            Children.Clear();

            if (this.width.IsNaN() || this.height.IsNaN()) return;
            if (this.width <= 0 || this.height <= 0) return;
            if (this.optALine == null || this.optALine.lineLengh <= 0) return;

            bool showChildren = false;

            if (!ActualSize)
            {
                if (ShowNegative)
                {
                    short max = optALine.lineData.Max();
                    short min = optALine.lineData.Min();
                    max = Math.Min(ShowALineMax, max);
                    int optALineHeight = max - min;
                    ScaleX = ActualSize ? 1.0 : (width / optALine.lineLengh);
                    ScaleY = (height - offsetY) / (optALineHeight == 0 ? ShowALineMax : optALineHeight);
                }
                else
                {
                    short max = optALine.lineData.Max();
                    short min = optALine.lineData.Min();
                    max = Math.Min(ShowALineMax, max);
                    min = (short)(min < 0 ? 0 : min);
                    int optALineHeight = max - min;
                    ScaleX = ActualSize ? 1.0 : (width / optALine.lineLengh);
                    ScaleY = (height - offsetY) / (optALineHeight == 0 ? ShowALineMax : optALineHeight);
                }
                showChildren = true;
                offsetX = 0;
            }

            //绘制曲线
            if (showChildren)
            {
                var polyline = new Polyline();
                //显示负值
                if (ShowNegative)
                {
                    for (int i = 0; i < optALine.lineLengh; i++)
                    {
                        var hValue = optALine.lineData[i] * ScaleY;
                        ////超过最高峰的部分不显示
                        //if (hValue > (height - offsetY)) continue;
                        //超过最高峰的部分显示到最高峰
                        hValue = Math.Min(hValue, height - offsetY);
                        polyline.Points.Add(new Point(i * ScaleX, height - hValue - offsetY));
                    }
                }
                else//不显示负值
                {
                    for (int i = 0; i < optALine.lineLengh; i++)
                    {
                        var hValue = (optALine.lineData[i] < 0 ? 0 : optALine.lineData[i]) * ScaleY;
                        ////超过最高峰的部分不显示
                        //if (hValue > (height - offsetY)) continue;
                        //超过最高峰的部分显示到最高峰
                        hValue = Math.Min(hValue, height - offsetY);
                        polyline.Points.Add(new Point(i * ScaleX, height - hValue - offsetY));
                    }
                }

                polyline.Stroke = Stroke;
                polyline.StrokeThickness = 1;
                Canvas.SetLeft(polyline, 0 - offsetX);
                polyline.IsHitTestVisible = false;
                Children.Add(polyline);
            }
        }

    }
}
